package win.smartown.android.scrollPager

import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.Scroller

/**
 * Created by smartown on 2017/6/21 10:56.
 * Description:
 */
class ScrollPager : LinearLayout, OnPagerScrollListener {

    var onScrollListener: OnScrollListener? = null
    var onPagerChangedListener: OnPagerChangedListener? = null
    var currentChildIndex = 0

    //是系统所能识别的被认为是滑动的最小距离
    private val scaledTouchSlop by lazy { ViewConfiguration.get(context).scaledTouchSlop }
    private val scroller: Scroller by lazy { Scroller(context, LinearInterpolator()) }
    private var startY = 0F

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init()
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init()
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
        init()
    }

    fun init() {
        orientation = VERTICAL
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (childCount > 0) {
            for (i in 0..(childCount - 1)) {
                getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec)
            }
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        if (childCount > 0) {
            when (ev?.action) {
                MotionEvent.ACTION_DOWN -> {
                    startY = ev.y
                }
                MotionEvent.ACTION_MOVE -> {
                    val deltaY = startY - ev.y
                    if (deltaY >= scaledTouchSlop) {
                        //手指向上滑出有效距离
                        val child = getChildAt(currentChildIndex)
                        if (child is ScrollState) {
                            return child.atBottom()
                        }
                    } else if (deltaY <= -scaledTouchSlop) {
                        //手指向下滑出有效距离
                        val child = getChildAt(currentChildIndex)
                        if (child is ScrollState) {
                            return child.atTop()
                        }
                    }
                }
            }
        }
        return false
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (childCount > 0 && scroller.isFinished) {
            notifyOnScroll()
            when (event?.action) {
                MotionEvent.ACTION_DOWN -> {
                    startY = event.y
                }
                MotionEvent.ACTION_MOVE -> {
                    scrollBy(0, (startY - event.y).toInt())
                    startY = event.y
                }
                MotionEvent.ACTION_UP -> {
                    if (currentChildIndex == 0 && scrollY < 0) {
                        scrollToChildAt(0)
                    } else if (currentChildIndex == childCount - 1 && scrollY > (childCount - 1) * height) {
                        scrollToChildAt(childCount - 1)
                    } else {
                        if (scrollY % height < (height / 2)) {
                            scrollToChildAt(scrollY / height)
                        } else {
                            scrollToChildAt(scrollY / height + 1)
                        }
                    }
                }
            }
        }
        return super.onTouchEvent(event)
    }

    fun scrollToChildAt(index: Int) {
        scroller.startScroll(0, scrollY, 0, index * height - scrollY)
        postInvalidate()
        currentChildIndex = index
        onPagerChangedListener?.onPagerChanged(this, index)
    }

    override fun computeScroll() {
        if (scroller.computeScrollOffset()) {
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(scroller.currX, scroller.currY)
            //必须调用该方法，否则不一定能看到滚动效果
            postInvalidate()
        }
        notifyOnScroll()
    }

    fun getTotalScrollDistance(): Int {
        val childTotalScrollDistance = (0..(childCount - 1)).sumBy { getChildAt(it).scrollY }
        return scrollY + childTotalScrollDistance
    }

    private fun notifyOnScroll() {
        onScrollListener?.onScroll(this, getTotalScrollDistance())
    }

    override fun onPagerScroll(scrollState: ScrollState, distance: Int) {
        notifyOnScroll()
    }

    interface OnScrollListener {

        fun onScroll(scrollPager: ScrollPager, distance: Int)

    }

    interface OnPagerChangedListener {

        fun onPagerChanged(scrollPager: ScrollPager, position: Int)

    }

}
